/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package firbi.base;

import android.app.Instrumentation;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
import android.test.ActivityInstrumentationTestCase2;
import android.test.InstrumentationTestCase;
import android.view.KeyEvent;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;

/** Instrumentation test case for using GPS button in map and list view and
 *  if the location is good or bad. 
 *  Goes through clicking on button, switching views, and clicking on list item.
 *  Checks that the correct view was opened as a result and if the map
 *  center has relocated to that GPS location. 
 * 
 * Can be run with the following command:
 * adb shell am instrument \
 * 	-e class firbi.base.SearchTestGPSUsage \
 *	-w firbi.base.tests/android.test.InstrumentationTestRunner
 *
 */
public class SearchTestGPSUsage extends ActivityInstrumentationTestCase2<Search> {
	private Location mLoc;
	private LocationManager mLocMan;
	private Search mActivity;
	private Instrumentation.ActivityMonitor mMonitor;
	
    public SearchTestGPSUsage() {
        super("firbi.base", Search.class);
    }
    
    /** Setup GPS location and the monitor that will watch for RouteView */
    @Override
    protected void setUp() throws Exception {
    	super.setUp();
    	mLoc = new Location(LocationManager.GPS_PROVIDER);
		mLoc.setTime(System.currentTimeMillis());
		mActivity = getActivity();
		mLocMan = (LocationManager)mActivity.getSystemService(Context.LOCATION_SERVICE);
    	mLocMan.setTestProviderEnabled(LocationManager.GPS_PROVIDER, true);
    	mLocMan.setTestProviderLocation(LocationManager.GPS_PROVIDER, mLoc);
    }
    
    /** Executes the test by going through user interactions and asserting
     *  that the monitor has seen the RouteView open. Tests GPS button first
     *  in map view then in list view. 
     */ 
    public void testGPSUsage() throws Exception {
    	MapView myMap = (MapView) mActivity.findViewById(R.id.map);
    	mMonitor = new Instrumentation.ActivityMonitor("firbi.base.StopView", null, true);
		this.getInstrumentation().addMonitor(mMonitor);
		
		/* Good location with bus stops */
		relocate(47.6198, -122.347);
		
    	Thread.sleep(2000);
    	assertEquals("No intents fired", 0, mMonitor.getHits());
    	
    	/* Hit GPS button and get stops */
    	sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
    	sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
    	sendKeys("ENTER");
    	Thread.sleep(4000);
    	
    	/* Use menu to switch to list view */
	    sendKeys(KeyEvent.KEYCODE_MENU);
	    sendKeys(KeyEvent.KEYCODE_DPAD_UP);
	    sendKeys("ENTER");
	    Thread.sleep(1000);
	    
    	/* Click on a list item */
	    sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
	    sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
	    sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
	    sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
	    sendKeys("ENTER");
	    Thread.sleep(500);
 
    	/* Check that RouteView was called -- but don't open the view */
    	assertEquals("Should have fired", 1, mMonitor.getHits()); 
 
    	
    	/* Test GPS usage in list view */
    	assertFalse("In list", getActivity().isMapView());
    	sendKeys(KeyEvent.KEYCODE_DPAD_UP);
    	sendKeys(KeyEvent.KEYCODE_DPAD_UP);
    	sendKeys(KeyEvent.KEYCODE_DPAD_UP);
    	sendKeys(KeyEvent.KEYCODE_DPAD_UP);
    	
    	/* Now try another good location */
    	relocate(47.623, -122.3482);
    	
    	/* Hit GPS button */
    	sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
    	sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
    	sendKeys("ENTER");
    	Thread.sleep(4000);
    	
    	/* Switch to map to check center and changed to location */
    	switchViewType();
    	assertTrue("In map", getActivity().isMapView());
    	GeoPoint newCenter = myMap.getMapCenter();
    	boolean correctCenter =( (newCenter.getLatitudeE6()==(int)(47.623*1E6)) && (newCenter.getLongitudeE6()==(int)(-122.3482*1E6)) );
    	assertTrue("Recentered on good GPS", correctCenter);
    	
    	doAClickinList();
	    
    	/* Check that RouteView was not called because there are no stops */
    	assertEquals("Should have fired", 2, mMonitor.getHits());
    } 
    
    /**
     * Tests GPS usage when the location is bad and does not contains any bus stops. 
     * @throws Exception
     */
    public void testGPSUsageBad() throws Exception {
    	MapView myMap = (MapView)getActivity().findViewById(R.id.map);
		mMonitor = new Instrumentation.ActivityMonitor("firbi.base.StopView", null, true);
		this.getInstrumentation().addMonitor(mMonitor);
		
    	/* Try a bad location */
    	relocate(0.0, 100.45);
    	
    	/* Hit GPS button */
    	sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
    	sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
    	sendKeys("ENTER");
    	Thread.sleep(4000);
    	
    	GeoPoint newCenter = myMap.getMapCenter();
    	boolean correctCenter =( (newCenter.getLatitudeE6()==0) && (newCenter.getLongitudeE6()==(int)(100.45*1E6)) ); 
    	assertTrue("Recentered even if bad GPS", correctCenter);
    
    	/* Click on a bus stop item */
    	doAClickinList();
	    
    	/* Check that RouteView was not called because there are no stops */
    	assertEquals("Should have not fired", 0, mMonitor.getHits());
    }
    
    /**
     * Relocates the GPS position to the coordinates provided and sleeps
     * so the location will be set. 
     * @param lat: Latitude of new location. 
     * @param lon: Longitude of new location.
     * @throws Exception: If sleeping fails. 
     */
    private void relocate(double lat, double lon) throws Exception {
		mLoc.setLatitude(lat);
		mLoc.setLongitude(lon);
		mLoc.setTime(System.currentTimeMillis());
		mActivity = getActivity();
		LocationManager locMan = (LocationManager)mActivity.getSystemService(Context.LOCATION_SERVICE);
    	locMan.setTestProviderEnabled(LocationManager.GPS_PROVIDER, true);
    	locMan.setTestProviderLocation(LocationManager.GPS_PROVIDER, mLoc);
    	Thread.sleep(4000);
    }
    
    /**
     * Switches the views from map to list and vice versa by going through the menu.
     * 
     * @throws Exception: If sleep fails
     */
    private void switchViewType() throws Exception {
		/* Use menu to switch to map or list view */		
    	sendKeys(KeyEvent.KEYCODE_MENU);
    	sendKeys(KeyEvent.KEYCODE_DPAD_UP);
    	sendKeys("ENTER");
    	Thread.sleep(1000);
    }
    
    /**
     * Performs a list item click. If in map view, then it
     * will use the menu to switch to list. 
     * @throws Exception: If sleep fails
     */
    private void doAClickinList() throws Exception {
    	/* Switch to list view if not in it already */
    	if (getActivity().isMapView())
    		switchViewType();
	    
    	/* Click on a list item */
	    sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
	    sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
	    sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
	    sendKeys("ENTER");
	    Thread.sleep(500);
    }
}
